package my.algo.data;

import java.util.Iterator;

/**
 * @author fengbo
 * @date 2018/4/16
 */
public class ArrayList<T> implements List<T> {

    private static final int DEFAULT_CAPACITY = 10;

    private Object[] elementData;

    private int size;

    public ArrayList() {
        this(DEFAULT_CAPACITY);
    }

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            elementData = new Object[DEFAULT_CAPACITY];
        } else {
            throw new IndexOutOfBoundsException("Create ArrayList index out of bounds!");
        }
    }

    @Override
    public boolean add(T element) {
        ensureCapacityInternal();
        elementData[size++] = element;
        return true;
    }

    @Override
    public boolean add(T element, int index) {
        checkIndex(index);
        ensureCapacityInternal();
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        size++;
        return false;
    }

    private void ensureCapacityInternal() {
        if (size >= elementData.length) {
            Object[] oldArr = elementData;
            elementData = new Object[elementData.length * 2];
            System.arraycopy(oldArr, 0, elementData, 0, oldArr.length);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public T get(int i) {
        checkIndex(i);
        return (T) elementData[i];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public T remove(int index) {
        checkIndex(index);
        @SuppressWarnings("unchecked")
        T item = (T) elementData[index];
        elementData[index] = null;
        System.arraycopy(elementData, index + 1, elementData, index, size - index);
        size--;
        return item;
    }

    private void checkIndex(int i) {
        if (i < 0 || i > size) {
            throw new IndexOutOfBoundsException("ArrayList index out of bounds!");
        }
    }

    @Override
    public Iterator iterator() {
        return new Itr();
    }

    public class Itr implements Iterator<T> {

        private int cursor = 0;

        @Override
        public boolean hasNext() {
            return cursor != size;
        }

        @Override
        @SuppressWarnings("unchecked")
        public T next() {
            return (T) elementData[cursor++];
        }
    }

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(1);
        list.add(1);
        list.add(2);
        list.add(4, 1);

        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}
